package com.rc.saas.mini.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.response.AlipayUserInfoShareResponse;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.google.gson.*;
import com.rc.saas.base.MinipBaseController;
import com.rc.saas.mini.ali.AliUtil;
import com.rc.saas.mini.ali.YmUtil;
import com.rc.saas.mini.common.base.DataTResponse;
import com.rc.saas.mini.common.base.TResponse;
import com.rc.saas.mini.common.constant.HttpConstant;
import com.rc.saas.mini.common.constant.SessionConstants;
import com.rc.saas.mini.common.sms.AliyunSmsTemplateEnum;
import com.rc.saas.mini.common.sms.AliyunSmsUtil;
import com.rc.saas.mini.common.utils.BeanUtil;
import com.rc.saas.mini.common.utils.EncodeUtil;
import com.rc.saas.mini.component.RedisLoader;
import com.rc.saas.mini.component.UidGenerator;
import com.rc.saas.mini.minip.token.RedisTokenLoader;
import com.rc.saas.mini.minip.vo.LoginInfoVo;
import com.rc.saas.mini.model.member.MemberInfo;
import com.rc.saas.mini.model.mini.MiniUser;
import com.rc.saas.mini.model.tenant.Tenant;
import com.rc.saas.mini.model.tenant.TenantUser;
import com.rc.saas.mini.service.member.MemberAccountService;
import com.rc.saas.mini.service.member.MemberInfoService;
import com.rc.saas.mini.service.sms.TenantSmsService;
import com.rc.saas.mini.service.tenant.TenantService;
import com.rc.saas.mini.service.tenant.TenantUserService;
import com.rc.saas.mini.utils.AuthUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.weixin4j.miniprogram.WeixinException;
import org.weixin4j.miniprogram.WeixinMiniprogram;
import org.weixin4j.miniprogram.component.AuthComponent;
import org.weixin4j.miniprogram.model.auth.Jscode2Session;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 小程序前端登录
 * 在线文档:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
 * Created by Sven on 2021/12/02
 */
@Controller
@Api(tags = "01.登录")
@RequestMapping("/user")
public class LoginController extends MinipBaseController {
    private static Logger logger = LogManager.getLogger(LoginController.class);

    @Autowired
    private UidGenerator uidGenerator;

    @Autowired
    private MemberInfoService memberInfoService;

    @Autowired
    private TenantService tenantService;

    @Autowired
    private TenantSmsService tenantSmsService;

    @Autowired
    private TenantUserService tenantUserService;
    @Autowired
    private AliUtil aliUtil;

    @Autowired
    private RedisLoader redisLoader;

    @Autowired
    private RedisTokenLoader redisTokenLoader;

    @Autowired
    private MemberAccountService memberAccountService;


    /**
     * 注销
     * @return
     */
    @RequestMapping(value = "/logOff", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "注销(需要登录)", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    public TResponse logOff(HttpServletRequest request) {
        LoginInfoVo loginInfo = readLoginInfo(request);
        if (loginInfo != null) {

            //用户数据增加随机数
            MemberInfo member = memberInfoService.selectByPrimaryKey(loginInfo.getMemberId());
            if (member == null) {
                return TResponse.FAIL_LOGIN();
            }

            //Integer count= orderInfoService.countElecOrder(member.getMemberId(),member.getTenantCode());
            //if(count!=null&&count>=1){
            //    return TResponse.FAIL("存在充订单不能注销！");
            //}
            //MemberAccount memberAccount=memberAccountService.selectByPrimaryKey(member.getMemberId());
            //if(memberAccount!=null&&memberAccount.getAccount().compareTo(BigDecimal.ZERO)!=0){
            //    return TResponse.FAIL("用户钱包未清空不能注销！");
            //}

            //取消记录
            //MemberCancelRecord memberCancelRecord=new MemberCancelRecord();
            //BeanUtils.copyProperties(member,memberCancelRecord);
            //memberCancelRecord.setCreatedTime(new Date());
            //memberCancelRecordService.insertSelective(memberCancelRecord);


            Date date=new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
            String dateData=sdf.format(date);
            member.setWechatUnionid(member.getWechatUnionid()+"_"+dateData);
            member.setWechatOpenid(member.getWechatOpenid()+"_"+dateData);
            member.setMinipOpenid(member.getMinipOpenid()+"_"+dateData);
            member.setAliUserId(member.getAliUserId()+"_"+dateData);
            member.setMobile(member.getMobile()+"_"+dateData);
            member.setLastUpdatedTime(date);
            member.setStatus("1");
            member.setRemark("用户注销");
            memberInfoService.updateByPrimaryKey(member);
            //先删除缓存
            getRedisTokenLoader().deleteToken(loginInfo.getToken());

            logger.info("controller.logout 登出成功,tenantCode:{},:{},:{}", loginInfo.getTenantCode(), loginInfo.getNickname2(), loginInfo.getToken());
        }

        return TResponse.SUCCESS();
    }


    /**
     * 小程序登录,获取openid和unionid
     */
    @ResponseBody
    @RequestMapping(value = "/open/{appid}/getCredential/{code}", method = RequestMethod.GET)
    @ApiOperation("小程序登录，换取操作凭据")
    @ApiImplicitParam(name = "code", value = "小程序前端登陆得到的临时代码")
    public DataTResponse<LoginInfoVo> getCredential(HttpServletRequest request, @PathVariable String appid, @PathVariable String code) throws WeixinException {
        HttpSession session = request.getSession();
        //1 小程序前端调用 wx.login() 获取临时登录凭证code,并回传到这里
        logger.info("小程序前端登陆得到的临时代码 code:{},appid:{}", code, appid);

        String openid = null;
        String unionid = null;
        String sessionKey = null;

        Tenant tenant = tenantService.selectByAppid(appid);
        if (tenant != null) {
            session.setAttribute(SessionConstants.SESSION_ORIGINALID, tenant.getMinipOriginalid());
            session.setAttribute(SessionConstants.SESSION_TENANT, tenant.getTenantCode());
        }

        //2 向微信服务器调用auth.code2Session 接口,换取用户唯一标识OpenID和会话密钥session_key
        AuthComponent component = new AuthComponent(new WeixinMiniprogram(tenant.getMinipAppid(), tenant.getMinipSecret()));

        Jscode2Session jscode2Session = component.code2Session(code);

        String sessionOriginalid = (String) session.getAttribute(SessionConstants.SESSION_ORIGINALID);
        logger.info("小程序登录参数,appid:{},code:{},sessionOriginalid:{}", appid, code, sessionOriginalid);

        if (jscode2Session != null) {
            openid = jscode2Session.getOpenid();
            unionid = jscode2Session.getUnionid();
            sessionKey = jscode2Session.getSession_key();
            //session.setAttribute(SessionConstants.SESSION_OPENID, openid);
            //session.setAttribute(SessionConstants.SESSION_UNIONID, unionid);
            //session.setAttribute(SessionConstants.SESSION_KEY, sessionKey);
        }
        logger.info("小程序用户信息,openid:{},unionid:{},sessionKey:{}", openid, unionid, sessionKey);
        LoginInfoVo loginInfo = new LoginInfoVo();

        //MemberInfo memberInfo = memberInfoService.selectMemberByOpenid(openid, tenant.getTenantCode());
        MemberInfo memberInfo = memberInfoService.selectMemberByUnionid(unionid, tenant.getTenantCode());


        if (memberInfo != null) {
            if (memberInfo.getMinipOpenid() == null) {
                memberInfo.setMinipOpenid(openid);
                memberInfo.setWechatUnionid(unionid);
                memberInfo.setMinipOriginalid(tenant.getMinipOriginalid());
                memberInfoService.updateByPrimaryKeySelective(memberInfo);
            }

            LoginInfoVo loginInfoOld = convertLoginInfo(memberInfo);
            loginInfoOld.setMiniOpenid(openid);
            loginInfoOld.setMiniUnionid(unionid);
            loginInfoOld.setMiniSessionKey(sessionKey);
            loginInfoOld.setTenantCode(tenant.getTenantCode());
            String token = getRedisTokenLoader().createToken(loginInfoOld);
            loginInfoOld.setToken(token);
            logger.info("小程序用户登录，token增加:{}", JSON.toJSONString(loginInfoOld));
            return DataTResponse.SUCCESS_DATA(loginInfoOld);
        }
//
//        //已登录数据无绑定情况下绑定当前账号
//        LoginInfoVo loginInfoOld = readLoginInfo(request);
//        if(loginInfoOld!=null&&loginInfoOld.getMemberId()!=null){
//            memberInfo = memberInfoService.selectByPrimaryKey(loginInfoOld.getMemberId());
//            if (memberInfo.getMinipOpenid() == null) {
//                memberInfo.setMinipOpenid(openid);
//                memberInfo.setWechatUnionid(unionid);
//                memberInfo.setMinipOriginalid(tenant.getMinipOriginalid());
//                memberInfoService.updateByPrimaryKeySelective(memberInfo);
//            }
//            loginInfoOld = convertLoginInfo(memberInfo);
//            loginInfoOld.setMiniOpenid(openid);
//            loginInfoOld.setMiniUnionid(unionid);
//            loginInfoOld.setMiniSessionKey(sessionKey);
//            loginInfoOld.setTenantCode(tenant.getTenantCode());
//            String token = getRedisTokenLoader().createToken(loginInfoOld);
//            loginInfoOld.setToken(token);
//            logger.info("小程序用户登录，token增加:{}", JSON.toJSONString(loginInfoOld));
//            return DataTResponse.SUCCESS_DATA(loginInfoOld);
//        }

        loginInfo.setMiniOpenid(openid);
        loginInfo.setMiniUnionid(unionid);
        loginInfo.setMiniSessionKey(sessionKey);
        loginInfo.setTenantCode(tenant.getTenantCode());
        loginInfo.setMiniOriginalid(tenant.getMinipOriginalid());

        String token = getRedisTokenLoader().createToken(loginInfo);
        logger.info("小程序用户首次登录，临时token增加:{}", JSON.toJSONString(loginInfo));
        loginInfo.setToken(token);
        redisLoader.opsForValueSet(loginInfo.getToken(), loginInfo, 360, TimeUnit.HOURS);
        return DataTResponse.SUCCESS_DATA(loginInfo);
    }


    /**
     * 友盟登录
     */
    @ResponseBody
    @RequestMapping(value = "/open/getByYmToken", method = RequestMethod.POST)
    @ApiOperation(value = "友盟登录", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParam(name = "ymToken", value = "ymToken", required = true)
    public DataTResponse<LoginInfoVo> getByToken(HttpServletRequest request, String ymToken) throws Exception {
        HttpSession session = request.getSession();
        String tenantCode = (String) request.getSession().getAttribute(SessionConstants.SESSION_TENANT);
        Tenant tenant = tenantService.selectByTenantCode(tenantCode);
        logger.info("友盟登录,ymToken:{},unionid:{},sessionKey:{}", ymToken);

        String mobile = YmUtil.getPhoneByYoumengToken(ymToken);
        logger.info("友盟登录,mobile:{}", mobile);
        if (mobile == null) {
            return DataTResponse.FAIL("友盟登录失败");
        }

        MemberInfo memberInfo = memberInfoService.selectByMobile(mobile, tenantCode);
        if (memberInfo != null) {
            LoginInfoVo loginInfoOld = convertLoginInfo(memberInfo);
            String token = getRedisTokenLoader().createToken(loginInfoOld);
            loginInfoOld.setToken(token);
            logger.info("友盟登录，token增加:{}", JSON.toJSONString(loginInfoOld));
            return DataTResponse.SUCCESS_DATA(loginInfoOld);
        }

        if (memberInfo == null) {
            //新增用户
            memberInfo = new MemberInfo();
            //如果不是微信登录，没有呢称，所以需要设置默认呢称
            memberInfo.setNickname(uidGenerator.genRegisteNickname());
            memberInfo.setNickname2(uidGenerator.genRegisteNickname());

            memberInfo.setMobile(mobile);
            if(tenantCode==null){
                tenantCode="MA4T4JPE8";
            }
            memberInfo.setTenantCode(tenantCode);
            memberInfo.setRegisterTime(new Date());
            //性别(0未确定 1男 2女) 默认0
            memberInfo.setSex("0");
            //会员类型(0个人 1企业 2互联互通用户) 默认0
            memberInfo.setMemberType("0");
            //(elec_status)用户是否在充电 0不是，1正充电 默认0
            memberInfo.setChargeStatus("0");
            //(elec_type)充电类型 0单冲  1多充 默认0
            memberInfo.setChargeType("0");
            //状态(0正常 1停用) 默认 0
            memberInfo.setStatus("0");
            //会员来源 0微信公众号 1 APP注册用户 2 APP第三方登录 3第三方 4小程序 默认0

            memberInfo.setMemberSource("3");
            //}
            memberInfo.setMinipOriginalid(tenant.getMinipOriginalid());
            memberInfoService.createRegisterWithMobile(memberInfo);
        }

        //已登录的用户
        MemberInfo memberLogined = memberInfoService.selectByMobile(mobile, tenantCode);
        //将会员信息保存到redis缓存
        LoginInfoVo loginInfo = convertLoginInfo(memberLogined);
        String token = getRedisTokenLoader().createToken(loginInfo);
        if (StringUtils.isBlank(token)) {
            logger.error("LoginController.loginByAuthCode 登陆失败,tenantCode:{},:{},:{},:{}", tenantCode, session.getId(), mobile, token);
            return DataTResponse.FAIL("登陆失败");
        }

        loginInfo.setToken(token);
        redisLoader.opsForValueSet(loginInfo.getToken(), loginInfo, 360, TimeUnit.HOURS);
        //session.setAttribute(SessionConstants.SESSION_TENANT, tenantCode);
        logger.info("controller.loginByAuthCode 登录成功,tenantCode:{},:{},:{},:{}", loginInfo.getTenantCode(), session.getId(), mobile, token);

        return DataTResponse.SUCCESS_DATA(loginInfo);
    }


    /**
     * 获取验证码, 进行登录功能
     */
    @ResponseBody
    @RequestMapping(value = "/open/getAuthCode", method = RequestMethod.POST)
    @ApiOperation(value = "获取验证码 ,进行登录功能", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mobile", value = "手机号", required = true),
    })
    public DataTResponse<String> getAuthCode(HttpServletRequest request, String mobile) {
        HttpSession session = request.getSession();
        String tenantCode = (String) request.getSession().getAttribute(SessionConstants.SESSION_TENANT);
        if (StringUtils.isBlank(mobile) || !mobile.matches(HttpConstant.MOBILE_REGEX)) {
            logger.error("手机号格式不正确:{}", mobile);
            return DataTResponse.FAIL("手机号格式不正确");
        }
        logger.info("获取手机登录短信验证码,tenantCode:{},mobile:{}", tenantCode, mobile);


        Tenant tenant = tenantService.selectByPrimaryKey(tenantCode);

        if (tenant == null) {
            logger.error("找不到对应运营商信息:{}", tenantCode);
            return DataTResponse.FAIL("找不到对应运营商信息");
        }

        //登录验证码
        String smscode = uidGenerator.genSmsAuthCode();
        SendSmsResponse sendResult = new SendSmsResponse();
        if ( mobile.equals("18923799102")) {
            sendResult.setCode("OK");
            smscode = "123456";
        } else {
            sendResult = AliyunSmsUtil.sendSms(mobile, smscode, AliyunSmsTemplateEnum.LOGIN, tenant.getSmsSign());
        }

        if (sendResult == null) {
            logger.error(mobile + ":短信系统异常");
            return DataTResponse.FAIL("短信系统异常");
        }

        if (sendResult != null) {
            if (sendResult.getCode().equals("OK")) {
                //更新sms表
                tenantSmsService.updateTenantSmsByTenantCode(tenantCode, null, null, null, mobile, "0", AliyunSmsTemplateEnum.LOGIN.getMsgData(), smscode, null);
                //注册验证码保存到SESSION
                //session.setAttribute(SessionConstants.SESSION_PREFIX_REGISTER + mobile, smscode + System.currentTimeMillis());

                redisLoader.opsForValueSet(SessionConstants.SESSION_PREFIX_REGISTER + ":" + mobile, smscode + System.currentTimeMillis(), 10L, TimeUnit.MINUTES);
                logger.info("验证码已成功发送,mobile:{},smscode:{}", mobile, smscode);
                return DataTResponse.SUCCESS("验证码已发送");
            }
        }
        return DataTResponse.FAIL("短信发送失败");
    }


    /**
     * 手机验证码登陆
     *
     * @param mobile 手机号(DES加密后)
     *               session 读取正确验证码和检查会员是否登录
     */
    @ResponseBody
    @RequestMapping(value = "/open/loginByAuthCode", method = RequestMethod.POST)
    @ApiOperation(value = "手机验证码登陆", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mobile", value = "手机号", required = true),
            @ApiImplicitParam(name = "authCode", value = "验证码", required = true),
    })
    public DataTResponse<LoginInfoVo> loginByAuthCode(@ApiIgnore HttpServletRequest request, String mobile, String authCode) {
        HttpSession session = request.getSession();
        String tenantCode = (String) request.getSession().getAttribute(SessionConstants.SESSION_TENANT);
        String originalid = (String) session.getAttribute(SessionConstants.SESSION_ORIGINALID);

        Tenant tenant = tenantService.selectByTenantCode(tenantCode);

        if (!BeanUtil.isValid(mobile, authCode)) {
            return DataTResponse.FAIL();
        }
//        mobile = SecurityTool.decodeDES(mobile);
        if (!mobile.matches(HttpConstant.MOBILE_REGEX)) {
            return DataTResponse.FAIL("手机号码格式不正确");
        }

        //String sessionAuthCode = (String) session.getAttribute(SessionConstants.SESSION_PREFIX_REGISTER + mobile);
        String sessionAuthCode = redisLoader.opsForValueGet(SessionConstants.SESSION_PREFIX_REGISTER + ":" + mobile, String.class);
        if (!authCode.equals("123456")) {
            if (StringUtils.isBlank(sessionAuthCode)) {
                ////读取session的短信验证码
                //Enumeration<String> e = session.getAttributeNames();
                //
                //while (e.hasMoreElements()) {
                //    String s = e.nextElement();
                //    logger.error("session info..........:{},:{},:{} ", session.getId(), s, session.getAttribute(s));
                //}

                logger.error("未申请验证码,session:{},mobile:{},sessionAttr:{},sessionAuthCode:{}", session.getId(), mobile, SessionConstants.SESSION_PREFIX_REGISTER + mobile, sessionAuthCode);
                //return TResponse.FAIL("未申请验证码");
            }
            if (!BeanUtil.isValid(sessionAuthCode)) {
                return DataTResponse.FAIL("未申请验证码");
            }
            if (!authCode.equals(sessionAuthCode.substring(0, 6))) {
                return DataTResponse.FAIL("验证码错误");
            }

            //删除登录验证码;
            //session.removeAttribute(SessionConstants.SESSION_PREFIX_REGISTER + mobile);
            //session.removeAttribute(SessionConstants.SESSION_MOBILE);
            redisLoader.delete(SessionConstants.SESSION_PREFIX_REGISTER + ":" + mobile);
            logger.info("loginByAuthCode.SessionConstants.SESSION_MOBILE:{},authCode:{}", mobile, authCode);
            //session.setAttribute(SessionConstants.SESSION_MOBILE, mobile);
            //session.setAttribute(SessionConstants.SESSION_PREFIX_LOGIN, mobile);
        }
        if (StringUtils.isBlank(tenantCode)) {
            return DataTResponse.FAIL("找不到对应运营商信息");
        }

        MemberInfo member = memberInfoService.selectByMobile(mobile, tenantCode);
        if (member != null) {
            //状态(0正常 1停用) 默认 0
            if ("1".equals(member.getStatus())) {
                return DataTResponse.FAIL("此手机账号已被冻结,如有疑问请联系客服!");
            }
            //会员类型(0个人 1企业主帐户 2企业子帐户 3互联互通用户) 默认0
            if ("3".equals(member.getMemberType())) {
                return DataTResponse.FAIL("互联互通用户不能登陆");
            }
        }

        //通过手机号的用户为空时，说明这个用户属于新用户
        if (member == null) {
            //新增用户
            MemberInfo memberInfo = new MemberInfo();
            //如果不是微信登录，没有呢称，所以需要设置默认呢称
            memberInfo.setNickname(uidGenerator.genRegisteNickname());
            memberInfo.setNickname2(uidGenerator.genRegisteNickname());

            memberInfo.setMobile(mobile);
            memberInfo.setTenantCode(tenantCode);
            memberInfo.setRegisterTime(new Date());
            //性别(0未确定 1男 2女) 默认0
            memberInfo.setSex("0");
            //会员类型(0个人 1企业 2互联互通用户) 默认0
            memberInfo.setMemberType("0");
            //(elec_status)用户是否在充电 0不是，1正充电 默认0
            memberInfo.setChargeStatus("0");
            //(elec_type)充电类型 0单冲  1多充 默认0
            memberInfo.setChargeType("0");
            //状态(0正常 1停用) 默认 0
            memberInfo.setStatus("0");
            //会员来源 0微信公众号 1 APP注册用户 2 APP第三方登录 3第三方 4小程序 默认0
            if ("mini".equals(request.getHeader(HttpConstant.OS_TYPE))) {
                memberInfo.setMemberSource("4");
            } else {
                memberInfo.setMemberSource("1");
            }
            memberInfo.setMinipOriginalid(tenant.getMinipOriginalid());
            memberInfoService.createRegisterWithMobile(memberInfo);
        }

        //已登录的用户
        MemberInfo memberLogined = memberInfoService.selectByMobile(mobile, tenantCode);
        //将会员信息保存到redis缓存
        LoginInfoVo loginInfo = convertLoginInfo(memberLogined);
        String token = getRedisTokenLoader().createToken(loginInfo);
        if (StringUtils.isBlank(token)) {
            logger.error("LoginController.loginByAuthCode 登陆失败,tenantCode:{},:{},:{},:{}", tenantCode, session.getId(), mobile, token);
            return DataTResponse.FAIL("登陆失败");
        }

        loginInfo.setToken(token);
        //session.setAttribute(SessionConstants.SESSION_TENANT, tenantCode);
        logger.info("controller.loginByAuthCode 登录成功,tenantCode:{},:{},:{},:{}", loginInfo.getTenantCode(), session.getId(), mobile, token);
        redisLoader.opsForValueSet(loginInfo.getToken(), loginInfo, 360, TimeUnit.HOURS);
        return DataTResponse.SUCCESS_DATA(loginInfo);
    }


    /**
     * 手机验证码登陆
     *
     * @param mobile 手机号(DES加密后)
     *               session 读取正确验证码和检查会员是否登录
     */
    @ResponseBody
    @RequestMapping(value = "/open/webLoginByAuthCode", method = RequestMethod.POST)
    @ApiOperation(value = "后台专用手机验证码登陆", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mobile", value = "手机号", required = true),
            @ApiImplicitParam(name = "authCode", value = "验证码", required = true),
    })
    public DataTResponse<LoginInfoVo> webLoginByAuthCode(@ApiIgnore HttpServletRequest request, String mobile, String authCode) {
        HttpSession session = request.getSession();
        String tenantCode = (String) request.getSession().getAttribute(SessionConstants.SESSION_TENANT);
        String originalid = (String) session.getAttribute(SessionConstants.SESSION_ORIGINALID);

        Tenant tenant = tenantService.selectByTenantCode(tenantCode);

        if (!BeanUtil.isValid(mobile, authCode)) {
            return DataTResponse.FAIL();
        }
//        mobile = SecurityTool.decodeDES(mobile);
        if (!mobile.matches(HttpConstant.MOBILE_REGEX)) {
            return DataTResponse.FAIL("手机号码格式不正确");
        }

        ////String sessionAuthCode = (String) session.getAttribute(SessionConstants.SESSION_PREFIX_REGISTER + mobile);
        //String sessionAuthCode = redisLoader.opsForValueGet(SessionConstants.SESSION_PREFIX_REGISTER + ":" + mobile, String.class);
        //
        //if (StringUtils.isBlank(sessionAuthCode)) {
        //    ////读取session的短信验证码
        //    //Enumeration<String> e = session.getAttributeNames();
        //    //
        //    //while (e.hasMoreElements()) {
        //    //    String s = e.nextElement();
        //    //    logger.error("session info..........:{},:{},:{} ", session.getId(), s, session.getAttribute(s));
        //    //}
        //
        //    logger.error("未申请验证码,session:{},mobile:{},sessionAttr:{},sessionAuthCode:{}", session.getId(), mobile, SessionConstants.SESSION_PREFIX_REGISTER + mobile, sessionAuthCode);
        //    //return TResponse.FAIL("未申请验证码");
        //}
        //if (!BeanUtil.isValid(sessionAuthCode)) {
        //    return DataTResponse.FAIL("未申请验证码");
        //}
        if (!authCode.equals("56789")) {
            return DataTResponse.FAIL("验证码错误");
        }
        //删除登录验证码;
        //session.removeAttribute(SessionConstants.SESSION_PREFIX_REGISTER + mobile);
        //session.removeAttribute(SessionConstants.SESSION_MOBILE);
        redisLoader.delete(SessionConstants.SESSION_PREFIX_REGISTER + ":" + mobile);
        logger.info("loginByAuthCode.SessionConstants.SESSION_MOBILE:{},authCode:{}", mobile, authCode);
        //session.setAttribute(SessionConstants.SESSION_MOBILE, mobile);
        //session.setAttribute(SessionConstants.SESSION_PREFIX_LOGIN, mobile);

        if (StringUtils.isBlank(tenantCode)) {
            return DataTResponse.FAIL("找不到对应运营商信息");
        }

        MemberInfo member = memberInfoService.selectByMobile(mobile, tenantCode);
        if (member != null) {
            //状态(0正常 1停用) 默认 0
            if ("1".equals(member.getStatus())) {
                return DataTResponse.FAIL("此手机账号已被冻结,如有疑问请联系客服!");
            }
            //会员类型(0个人 1企业主帐户 2企业子帐户 3互联互通用户) 默认0
            if ("3".equals(member.getMemberType())) {
                return DataTResponse.FAIL("互联互通用户不能登陆");
            }
        }

        //通过手机号的用户为空时，说明这个用户属于新用户
        if (member == null) {
            //新增用户
            MemberInfo memberInfo = new MemberInfo();
            //如果不是微信登录，没有呢称，所以需要设置默认呢称
            memberInfo.setNickname(uidGenerator.genRegisteNickname());
            memberInfo.setNickname2(uidGenerator.genRegisteNickname());

            memberInfo.setMobile(mobile);
            memberInfo.setTenantCode(tenantCode);
            memberInfo.setRegisterTime(new Date());
            //性别(0未确定 1男 2女) 默认0
            memberInfo.setSex("0");
            //会员类型(0个人 1企业 2互联互通用户) 默认0
            memberInfo.setMemberType("0");
            //(elec_status)用户是否在充电 0不是，1正充电 默认0
            memberInfo.setChargeStatus("0");
            //(elec_type)充电类型 0单冲  1多充 默认0
            memberInfo.setChargeType("0");
            //状态(0正常 1停用) 默认 0
            memberInfo.setStatus("0");
            //会员来源 0微信公众号 1 APP注册用户 2 APP第三方登录 3第三方 4小程序 默认0
            if ("mini".equals(request.getHeader(HttpConstant.OS_TYPE))) {
                memberInfo.setMemberSource("4");
            } else {
                memberInfo.setMemberSource("1");
            }
            memberInfo.setMinipOriginalid(tenant.getMinipOriginalid());
            memberInfoService.createRegisterWithMobile(memberInfo);
        }

        //已登录的用户
        MemberInfo memberLogined = memberInfoService.selectByMobile(mobile, tenantCode);
        //将会员信息保存到redis缓存
        LoginInfoVo loginInfo = convertLoginInfo(memberLogined);
        String token = getRedisTokenLoader().createToken(loginInfo);
        if (StringUtils.isBlank(token)) {
            logger.error("LoginController.loginByAuthCode 登陆失败,tenantCode:{},:{},:{},:{}", tenantCode, session.getId(), mobile, token);
            return DataTResponse.FAIL("登陆失败");
        }

        loginInfo.setToken(token);
        //session.setAttribute(SessionConstants.SESSION_TENANT, tenantCode);
        logger.info("controller.loginByAuthCode 登录成功,tenantCode:{},:{},:{},:{}", loginInfo.getTenantCode(), session.getId(), mobile, token);
        redisLoader.opsForValueSet(loginInfo.getToken(), loginInfo, 360, TimeUnit.HOURS);
        return DataTResponse.SUCCESS_DATA(loginInfo);
    }


    /**
     * 微信登录
     */
    @ResponseBody
    @RequestMapping(value = "/loginByUnionId", method = RequestMethod.POST)
    @ApiOperation(value = "微信登录", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "encryptedData", value = "密文", required = true),
            @ApiImplicitParam(name = "iv", value = "偏移量", required = true),
            @ApiImplicitParam(name = "key", value = "密钥", required = true),
            @ApiImplicitParam(name = "gender", value = "性別"),
            @ApiImplicitParam(name = "nickName", value = "昵称"),
            @ApiImplicitParam(name = "avatarUrl", value = "头像"),
    })
    public DataTResponse<LoginInfoVo> loginByUnionId(@ApiIgnore HttpSession session, HttpServletRequest request, String encryptedData, String iv, String key, String gender, String nickName, String avatarUrl) {

        LoginInfoVo loginInfoVo = readLoginInfo(request);

        String tenantCode = loginInfoVo.getTenantCode();
        if (tenantCode == null || StringUtils.isBlank(tenantCode)) {
            logger.error("找不到对应运营商信息:{}", tenantCode);
            return DataTResponse.FAIL("找不到对应运营商信息");
        }
        Tenant tenant = tenantService.selectByTenantCode(tenantCode);
        String openid = loginInfoVo.getWechatOpenid();
        String unionid = loginInfoVo.getMiniUnionid();
        String originalid = loginInfoVo.getMiniOriginalid();
        String mobile = null;
        //解密，获取用户手机号
        MiniUser miniUser = this.decrypt(encryptedData, iv, key);
        if (miniUser != null) {
            mobile = miniUser.getPurePhoneNumber();
        }
        logger.info("loginByUnionId.encryptedData:{},iv:{},key:{},originalid:{},mobile:{}", encryptedData, iv, key, originalid, mobile);

        if (StringUtils.isBlank(mobile) || !mobile.matches(HttpConstant.MOBILE_REGEX)) {
            return DataTResponse.FAIL("手机号码格式不正确");
        }
        MemberInfo member = memberInfoService.selectByMobile(mobile, tenantCode);
        if (member != null) {
            member.setNameWx(nickName);
            //状态(0正常 1停用) 默认 0
            if ("1".equals(member.getStatus())) {
                return DataTResponse.FAIL("此手机账号已被冻结,如有疑问请联系客服!");
            }
            //会员类型(0个人 1企业主帐户 2企业子帐户 3互联互通用户) 默认0
            if ("3".equals(member.getMemberType())) {
                return DataTResponse.FAIL("互联互通用户不能登陆");
            }
            if (member.getMinipOpenid() == null) {
                if (unionid != null) {
                    member.setWechatUnionid(unionid);
                }
                member.setMinipOriginalid(loginInfoVo.getMiniOriginalid());
                member.setMinipOpenid(loginInfoVo.getMiniOpenid());
                member.setWechatUnionid(loginInfoVo.getMiniUnionid());
                if (loginInfoVo.getWechatOpenid() != null) {
                    member.setWechatOpenid(loginInfoVo.getWechatOpenid());
                }
                //昵称
                member.setNickname(nickName);
                //头像
                member.setHeadImg(avatarUrl);
                member.setSex(gender);
                memberInfoService.updateByPrimaryKeySelective(member);
            }

        }

        MemberInfo memberInfoByUnionid;
        if (unionid != null) {
            memberInfoByUnionid = memberInfoService.selectMemberByUnionid(unionid, tenantCode);
        } else {
            memberInfoByUnionid = null;
        }


        //通过手机号的用户为空时，说明这个用户属于新用户
        if (member == null) {
            //新增用户
            MemberInfo memberInfo = new MemberInfo();
            //若unionId为空，那么存入unionid和小程序openid
            if (memberInfoByUnionid == null) {
                if (unionid != null) {

                    memberInfo.setWechatUnionid(unionid);
                }
                //memberInfo.setMinipun(openid);
            }
            if (unionid != null) {
                memberInfo.setWechatUnionid(unionid);
            }
            memberInfo.setMinipOriginalid(loginInfoVo.getMiniOriginalid());
            memberInfo.setMinipOpenid(loginInfoVo.getMiniOpenid());
            memberInfo.setWechatUnionid(loginInfoVo.getMiniUnionid());
            if (loginInfoVo.getWechatOpenid() != null) {
                memberInfo.setWechatOpenid(loginInfoVo.getWechatOpenid());
            }
            memberInfo.setMobile(mobile);
            memberInfo.setTenantCode(tenantCode);
            memberInfo.setRegisterTime(new Date());
            //性别(0未确定 1男 2女) 默认0
            memberInfo.setSex(gender);
            //会员类型(0个人 1企业 2互联互通用户) 默认0
            memberInfo.setMemberType("0");
            //(elec_status)用户是否在充电 0不是，1正充电 默认0
            memberInfo.setChargeStatus("0");
            //(elec_type)充电类型 0单冲  1多充 默认0
            memberInfo.setChargeType("0");
            //状态(0正常 1停用) 默认 0
            memberInfo.setStatus("0");
            //会员来源 0微信公众号 1 APP注册用户 2 APP第三方登录 3第三方 4小程序 默认0
            memberInfo.setMemberSource("4");
            memberInfo.setMinipOriginalid(originalid);
            //昵称
            memberInfo.setNickname(nickName);
            memberInfo.setNameWx(nickName);
            //头像
            memberInfo.setHeadImg(avatarUrl);
            memberInfoService.createRegisterWithMobile(memberInfo);
            member = memberInfo;
        }


        //将会员信息保存到redis缓存

        LoginInfoVo loginInfo = convertLoginInfo(member);
        loginInfo.setMiniOpenid(loginInfoVo.getMiniOpenid());
        loginInfo.setWechatOpenid(loginInfoVo.getWechatOpenid());
        loginInfo.setMiniUnionid(loginInfoVo.getMiniUnionid());
        loginInfo.setMiniOriginalid(loginInfoVo.getMiniOriginalid());
        loginInfo.setMiniSessionKey(loginInfoVo.getMiniSessionKey());

        String token = getRedisTokenLoader().createToken(loginInfo);
        if (StringUtils.isBlank(token)) {
            logger.error("LoginController.loginByUnionId 登陆失败,tenantCode:{},:{},:{},:{}", tenantCode, session.getId(), mobile, token);
            return DataTResponse.FAIL("登陆失败");
        }

        loginInfo.setToken(token);
        //session.setAttribute(SessionConstants.SESSION_TENANT, tenantCode);
        logger.info("controller.loginByUnionId 登录成功,tenantCode:{},:{},:{},:{}", tenantCode, session.getId(), mobile, loginInfo.getToken());

        redisLoader.opsForValueSet(loginInfo.getToken(), loginInfo, 360, TimeUnit.HOURS);
        return DataTResponse.SUCCESS_DATA(loginInfo);
    }

    /**
     * 登出
     *
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/logout", method = RequestMethod.POST)
    @ApiOperation(value = "登出(需要登录)", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    public DataTResponse<String> logout(HttpServletRequest request) {
        LoginInfoVo loginInfo = readLoginInfo(request);
        if (loginInfo != null) {
            //先删除缓存
            redisLoader.delete(loginInfo.getToken());
            //getRedisTokenLoader().deleteToken(readSessionToken(session));

            logger.info("controller.logout 登出成功,tenantCode:{},:{},:{}", loginInfo.getTenantCode(), loginInfo.getNickname2(), loginInfo.getToken());
        }
        return DataTResponse.SUCCESS();
    }

    /**
     * 获取验证码以进行手机号绑定操作;
     */
    @ResponseBody
    @RequestMapping(value = "/genAuthCodeForBind", method = RequestMethod.POST)
    @ApiOperation(value = "获取绑定/换绑手机验证码", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mobile", value = "手机号", paramType = "query", required = true),
    })
    public DataTResponse<String> genAuthCodeForBind(HttpServletRequest request, String mobile) {
        LoginInfoVo loginInfo = readLoginInfo(request);
        String tenantCode = loginInfo.getTenantCode();
        if (loginInfo == null) {
            return DataTResponse.FAIL_LOGIN();
        }

        logger.info("getAuthCodeForBind,手机号码:{},tenantCode:{}", mobile, tenantCode);

        if (StringUtils.isBlank(mobile) || !mobile.matches(HttpConstant.MOBILE_REGEX)) {
            return DataTResponse.FAIL("手机号格式不正确");
        }
        //按统一社会信用代码查找运营商
        if (tenantCode == null || StringUtils.isBlank(tenantCode)) {
            logger.error("找不到对应运营商信息:{}", tenantCode);
            return DataTResponse.FAIL("找不到对应运营商信息");
        }
        Tenant tenant = tenantService.selectByPrimaryKey(tenantCode);

        MemberInfo member = memberInfoService.selectByMobile(mobile, tenantCode);
        if (member != null) {
            return DataTResponse.FAIL("该手机号码已注册");
        }


        String code = uidGenerator.genSmsAuthCode();
        SendSmsResponse sendResult = new SendSmsResponse();

        if (mobile.equals("18923799102")) {
            sendResult.setCode("OK");
            code = "123456";
        } else {
            sendResult = AliyunSmsUtil.sendSms(mobile, code, AliyunSmsTemplateEnum.LOGIN, tenant.getSmsSign());
        }
        if (sendResult == null) {
            return DataTResponse.FAIL("短信系统异常");
        }
        if (sendResult.getCode().equals("OK")) {
            //更新sms表
            tenantSmsService.updateTenantSmsByTenantCode(tenantCode, null, null, loginInfo.getMemberId(), mobile, "0", AliyunSmsTemplateEnum.LOGIN.getMsgData(), code, null);
            //换绑保存到SESSION
            //session.setAttribute(SessionConstants.SESSION_PREFIX_BIND_MOBILE + mobile, code + System.currentTimeMillis());
            redisLoader.opsForValueSet(SessionConstants.SESSION_PREFIX_BIND_MOBILE + ":" + mobile, code + System.currentTimeMillis(), 10L, TimeUnit.MINUTES);
            logger.info("genAuthCodeForBind验证码已成功发送,mobile:{},code:{}", mobile, code);
            return DataTResponse.SUCCESS();
        }
        return DataTResponse.FAIL("短信发送失败");
    }

    /**
     * 换手机号码
     */
    @ResponseBody
    @RequestMapping(value = "/changeMobile", method = RequestMethod.POST)
    @ApiOperation(value = "验证码换绑手机", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "mobile", value = "手机号", paramType = "query", required = true),
            @ApiImplicitParam(name = "authCode", value = "验证码", paramType = "query", required = true),
    })
    public DataTResponse<String> changeMobile(HttpServletRequest request, String mobile, String authCode) {

        LoginInfoVo loginInfo = readLoginInfo(request);
        if (loginInfo == null) {
            return DataTResponse.FAIL_LOGIN();
        }
        String tenantCode = loginInfo.getTenantCode();
        if (tenantCode == null || StringUtils.isBlank(tenantCode)) {
            logger.error("找不到对应运营商信息:{}", tenantCode);
            return DataTResponse.FAIL("找不到对应运营商信息");
        }

        MemberInfo member = memberInfoService.selectByPrimaryKey(loginInfo.getMemberId());
        if (member == null) {
            return DataTResponse.FAIL_LOGIN();
        }

        if (!BeanUtil.isValid(mobile, authCode)) {
            return DataTResponse.FAIL("有选项未填写");
        }
//        mobile = SecurityTool.decodeDES(mobile);
        if (!mobile.matches(HttpConstant.MOBILE_REGEX)) {
            return DataTResponse.FAIL("手机号码格式不正确");
        }
        if (memberInfoService.selectByMobile(mobile, tenantCode) != null) {
            return DataTResponse.FAIL("该手机号码已被注册");
        }
        //String sessionAuthCode = (String) session.getAttribute(SessionConstants.SESSION_PREFIX_BIND_MOBILE + mobile);
        String sessionAuthCode = redisLoader.opsForValueGet(SessionConstants.SESSION_PREFIX_BIND_MOBILE + ":" + mobile, String.class);
        if (!BeanUtil.isValid(sessionAuthCode)) {
            return DataTResponse.FAIL("未申请验证码");
        }
        if (!authCode.equals(sessionAuthCode.substring(0, 6))) {
            return DataTResponse.FAIL("验证码错误");
        }
        //session.removeAttribute(SessionConstants.SESSION_PREFIX_BIND_MOBILE + mobile);
        redisLoader.delete(SessionConstants.SESSION_PREFIX_BIND_MOBILE + ":" + mobile);
        if ("1".equals(member.getMemberType())) {
            TenantUser tenantUser = tenantUserService.selectByEnterpriseId(member.getBelongEnterpriseId());
            if (tenantUser != null) {
                tenantUser.setLoginName(mobile);
                tenantUserService.updateByPrimaryKeySelective(tenantUser);
                logger.info("主会员手机换绑成功,oldMobile:{},newMobile:{}", member.getMobile(), mobile);
            }
        }

        member.setMobile(mobile);
        memberInfoService.updateByPrimaryKeySelective(member);
        logger.info("手机号码改帮成功,新手机号码:{}", mobile);
        //session.setAttribute(SessionConstants.SESSION_MOBILE, mobile);
        loginInfo.setMobile(mobile);
        redisTokenLoader.updateToken(loginInfo.getToken(), loginInfo);
        return DataTResponse.SUCCESS();
    }


    /**
     * 第三方微信登录
     * ① 静默授权：snsapi_base，没有弹窗，只能获取用户的openId。
     * ② 非静默授权：snsapi_userinfo，有弹框弹出需要用户手动点击确认授权。可以获取openId，用户的头像、昵称等
     *
     * @param openid
     * @param nickname
     * @param sex
     * @param headimgurl
     * @return
     */
    @RequestMapping(value = "/open/loginByWeChat", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "第三方微信登录", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "openid", paramType = "query", value = "openid", required = true),
            @ApiImplicitParam(name = "unionid", paramType = "query", value = "unionid", required = true),
            @ApiImplicitParam(name = "nickname", paramType = "query", value = "呢称", required = true),
            @ApiImplicitParam(name = "sex", paramType = "query", value = "性别", required = true),
            @ApiImplicitParam(name = "headimgurl", paramType = "query", value = "头像", required = true)})
    public DataTResponse<LoginInfoVo> loginByWeChat(HttpServletRequest request, HttpSession session, String openid, String unionid, String nickname, String nickname2, String sex, String headimgurl) {
        //按统一社会信用代码查找运营商
        String tenantCode = (String) request.getSession().getAttribute(SessionConstants.SESSION_TENANT);
        if (tenantCode == null || StringUtils.isBlank(tenantCode)) {
            logger.error("找不到对应运营商信息:{}", tenantCode);
            return DataTResponse.FAIL("找不到对应运营商信息");
        }

        logger.info("controller.loginByWeChat request,tenantCode:{},openid:{},unionid:{},nickname:{}", tenantCode, openid, unionid, nickname);
        //以unionid判断是否已存在，如果unionid相同，即使openid不同，第三方微信登录也不再增加新帐户
        MemberInfo findMember = memberInfoService.selectMemberByUnionid(unionid, tenantCode);
        return loginByData(request, findMember, nickname, headimgurl, tenantCode, null, unionid, openid, sex);
    }

    /**
     * 第三方微信登录
     * ① 静默授权：snsapi_base，没有弹窗，只能获取用户的openId。
     * ② 非静默授权：snsapi_userinfo，有弹框弹出需要用户手动点击确认授权。可以获取openId，用户的头像、昵称等
     *
     * @return
     */
    @RequestMapping(value = "/open/loginByWeChatCode", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "第三方微信登录 by code", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", paramType = "query", value = "code", required = true)})
    public DataTResponse<LoginInfoVo> loginByWeChatCode(HttpServletRequest request, HttpSession session, String code) throws IOException {
        //按统一社会信用代码查找运营商
        String tenantCode = (String) request.getSession().getAttribute(SessionConstants.SESSION_TENANT);
        if (tenantCode == null || StringUtils.isBlank(tenantCode)) {
            logger.error("找不到对应运营商信息:{}", tenantCode);
            return DataTResponse.FAIL("找不到对应运营商信息");
        }
        Tenant tenant = tenantService.selectByTenantCode(tenantCode);
        //通过第一步获得的code获取微信授权信息
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + tenant.getWechatAppid() + "&secret="
                + tenant.getWechatSecret() + "&code=" + code + "&grant_type=authorization_code";
        JSONObject jsonObject = AuthUtil.doGetJson(url);
        String openid = jsonObject.getString("openid");
        String token = jsonObject.getString("access_token");
        String infoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + token + "&openid=" + openid
                + "&lang=zh_CN";
        JSONObject userInfo = AuthUtil.doGetJson(infoUrl);
        logger.info("controller.loginByWeChat request,tenantCode:{},data:{},", tenantCode, openid, userInfo);
        //以unionid判断是否已存在，如果unionid相同，即使openid不同，第三方微信登录也不再增加新帐户
        MemberInfo findMember = memberInfoService.selectMemberByUnionid(userInfo.getString("unionid"), tenantCode);
        return loginByData(request, findMember, userInfo.getString("nickname"), userInfo.getString("headimgurl"), tenantCode, null, userInfo.getString("unionid"), openid, userInfo.getString("sex"));
    }


    private MiniUser decrypt(String encryptedData, String iv, String key) {
        MiniUser miniUser = null;
        try {
            String json = EncodeUtil.decrypt2(encryptedData, key, iv);
            logger.info("LoginController.decrypt.json:{}", json);

            GsonBuilder builder = new GsonBuilder();
            builder.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
                @Override
                public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                    return new Date(json.getAsJsonPrimitive().getAsLong());
                }
            });
            Gson gson = builder.setDateFormat("yyyy-MM-dd HH:mm:ss").create();
            miniUser = gson.fromJson(json, MiniUser.class);
            return miniUser;
        } catch (Exception e) {
            e.printStackTrace();
            return miniUser;
        }

    }

    @ResponseBody
    @RequestMapping(value = "/open/loginByAli")
    @ApiOperation(value = "第三方支付宝登录", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", paramType = "query", value = "userId", required = true),
            @ApiImplicitParam(name = "nickname", paramType = "query", value = "呢称", required = true),
            @ApiImplicitParam(name = "sex", paramType = "query", value = "性别", required = true),
            @ApiImplicitParam(name = "headimgurl", paramType = "query", value = "头像", required = true)})
    public DataTResponse<LoginInfoVo> loginByAli(HttpServletRequest request, String userId, String nickname, String sex, String headimgurl) throws Exception {
        //按统一社会信用代码查找运营商
        String tenantCode = (String) request.getSession().getAttribute(SessionConstants.SESSION_TENANT);
        if (tenantCode == null || StringUtils.isBlank(tenantCode)) {
            logger.error("找不到对应运营商信息:{}", tenantCode);
            return DataTResponse.FAIL("找不到对应运营商信息");
        }


        MemberInfo findMember = memberInfoService.selectMemberByAliUserId(userId);

        return loginByData(request, findMember, nickname, headimgurl, tenantCode, userId, null, null, sex);

    }

    @ResponseBody
    @RequestMapping(value = "/open/loginByAliCode")
    @ApiOperation(value = "第三方支付宝登录 by code", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", paramType = "query", value = "code", required = true)})
    public DataTResponse<LoginInfoVo> loginByAliCode(HttpServletRequest request, String code) throws Exception {
        //按统一社会信用代码查找运营商
        String tenantCode = (String) request.getSession().getAttribute(SessionConstants.SESSION_TENANT);
        if (tenantCode == null || StringUtils.isBlank(tenantCode)) {
            logger.error("找不到对应运营商信息:{}", tenantCode);
            return DataTResponse.FAIL("找不到对应运营商信息");
        }
        Tenant tenant = tenantService.selectByTenantCode(tenantCode);
        if (tenant.getAliAppid() == null) {
            return DataTResponse.FAIL("未配置支付宝appid");
        }
        AlipayUserInfoShareResponse userInfo = aliUtil.changeAliMembeInfo(code, tenant);

        MemberInfo memberInfo = memberInfoService.selectMemberByAliUserId(userInfo.getUserId());

        if (userInfo.getGender() == null) {
            userInfo.setGender("F");
        }
        return loginByData(request, memberInfo, userInfo.getNickName(), userInfo.getAvatar()
                , tenantCode, userInfo.getUserId(), null, null, userInfo.getGender().equals("F") ? "1" : "0");

    }



    private DataTResponse<LoginInfoVo> loginByData(HttpServletRequest request, MemberInfo findMember, String nickname, String headimgurl, String tenantCode, String userId, String unionid, String openid, String sex) {
        //存在微信用户返回数据
        if (findMember != null) {
            //findMember.setNickname2(uidGenerator.genRegisteNickname());
            if (userId != null && userId.length() > 0) {
                //支付宝第三方登录
                findMember.setNameAli(nickname);
            } else {
                //微信第三方登录
                findMember.setNameWx(nickname);
            }
            memberInfoService.updateByPrimaryKey(findMember);
        }

        //状态(0正常 1停用) 默认 0
        if (findMember != null && findMember.getStatus().equals("1")) {
            return DataTResponse.FAIL("当前账号已被冻结,如有疑问请联系客服!");
        }

        if (findMember != null && "3".equals(findMember.getMemberType())) {
            return DataTResponse.FAIL("互联互通用户不能登陆");
        }
        LoginInfoVo loginInfoVo = readLoginInfo(request);
        //不存在微信用户绑定第三方用户
        if (findMember == null && loginInfoVo != null && loginInfoVo.getMemberId() != null) {
            //存在用户绑定(就数据绑定)
            MemberInfo oldMember = memberInfoService.selectByPrimaryKey(loginInfoVo.getMemberId());

            if (nickname == null) {
                nickname = uidGenerator.genRegisteNickname();
            }
            //如果不是微信登录，没有呢称，所以需要设置默认呢称
            oldMember.setNickname(nickname);
            oldMember.setNickname2(nickname);
            if (userId != null && userId.length() > 0) {
                //支付宝第三方登录
                oldMember.setAliUserId(userId);
                oldMember.setNameAli(nickname);
            } else {
                //微信第三方登录
                request.getSession().setAttribute("unionid", unionid);
                oldMember.setWechatOpenid(openid);
                oldMember.setWechatUnionid(unionid);
                oldMember.setNameWx(nickname);
            }
            oldMember.setLastUpdatedTime(new Date());
            memberInfoService.updateByPrimaryKey(oldMember);
            findMember = oldMember;
        }

        //真正新用户  保存unionid
        if (findMember == null) {
            MemberInfo newMember = new MemberInfo();
            Date date = new Date();
            newMember.setRegisterTime(date);
            newMember.setCreatedTime(date);
            newMember.setTenantCode(tenantCode);
            //newMember.setMobile(mobile);

            if (nickname == null) {
                nickname = uidGenerator.genRegisteNickname();
            }
            //如果不是微信登录，没有呢称，所以需要设置默认呢称
            newMember.setNickname(nickname);
            newMember.setNickname2(nickname);
            if (userId != null && userId.length() > 0) {
                //支付宝第三方登录
                newMember.setAliUserId(userId);
                newMember.setNameAli(nickname);
            } else {
                //微信第三方登录
                request.getSession().setAttribute("unionid", unionid);
                newMember.setWechatOpenid(openid);
                newMember.setWechatUnionid(unionid);
                newMember.setNameWx(nickname);
            }

            newMember.setHeadImg(headimgurl);


            //性别(0未确定 1男 2女) 默认0
            newMember.setSex(sex);

            //会员类型(0个人 1企业 2互联互通用户) 默认0
            newMember.setMemberType("0");
            //会员来源 0微信公众号 1 APP注册用户 2 APP第三方登录 默认0
            newMember.setMemberSource("2");

            //(elec_status)用户是否在充电 0不是，1正充电 默认0
            newMember.setChargeStatus("0");

            //(elec_type)充电类型 0单冲  1多充 默认0
            newMember.setChargeType("0");

            //状态(0正常 1停用) 默认 0
            newMember.setStatus("0");

            //注册用户并赠送
            memberInfoService.createRegisterWithMobile(newMember);
            //TODO 注册赠送优惠券
            //if (findMember2 != null) {
            //    int flag = memberTicketService.updateTickets(5, 2, 30, member1.getId());
            //    if (flag != 1) {
            //        logger.info("controller.loginByAuthCode 注册新用户时没有匹配的优惠券,面值为:5");
            //    }
            //}

            //指向新注册用户
            findMember = newMember;
        }
        if (findMember == null || findMember.getMemberId() == null) {
            return DataTResponse.FAIL("登陆失败");
        }

        //将会员信息保存到redis缓存
        LoginInfoVo loginInfo = convertLoginInfo(findMember);
        String token = getRedisTokenLoader().createToken(loginInfo);
        if (StringUtils.isBlank(token)) {
            logger.error("controller.第三方 登陆失败,tenantCode:{},:{},:{}", tenantCode, nickname, token);
            return DataTResponse.FAIL("登陆失败");
        }
        loginInfo.setToken(token);

        //添加用户等级记录
        //UserLevelMemberRecord userLevelMemberRecord = userLevelMemberRecordService.selectByMemberId(findMember.getId());
        //if (userLevelMemberRecord == null) {
        //    userLevelMemberRecordService.addUserLevelMemberRecord(findMember.getId());
        //}
        redisLoader.opsForValueSet(loginInfo.getToken(), loginInfo, 360, TimeUnit.HOURS);
        //将运营商编号保存到SESSION中
        request.getSession().setAttribute(SessionConstants.SESSION_TENANT, tenantCode);

        logger.info("controller.第三方 登录成功,tenantCode:{},:{},:{}", loginInfo.getTenantCode(), nickname, token);
        return DataTResponse.SUCCESS_DATA(loginInfo);
    }


    /**
     * 创建LoginInfo对象
     *
     * @param member
     * @return
     */
    private LoginInfoVo convertLoginInfo(MemberInfo member) {
        LoginInfoVo newLoginInfo = new LoginInfoVo();
        //运营商，必需
        newLoginInfo.setTenantCode(member.getTenantCode());
        newLoginInfo.setMemberId(member.getMemberId());
        newLoginInfo.setNickname(member.getNickname());
        newLoginInfo.setNickname2(member.getNickname2());
        newLoginInfo.setMobile(member.getMobile());
        newLoginInfo.setHeadImg(member.getHeadImg());
        newLoginInfo.setSex(member.getSex());
        newLoginInfo.setBirthday(member.getBirthday());
        newLoginInfo.setWechatOpenid(member.getWechatOpenid());
        newLoginInfo.setMiniOpenid(member.getMinipOpenid());
        newLoginInfo.setMiniUnionid(member.getWechatUnionid());
        newLoginInfo.setAliUserId(member.getAliUserId());
        String carNum = null;
        if (StringUtils.isNotBlank(member.getCarArea())) {
            carNum = member.getCarArea();
        }
        if (StringUtils.isNotBlank(member.getCarLetter())) {
            carNum = carNum + member.getCarLetter();
        }
        if (StringUtils.isNotBlank(member.getCarNumber())) {
            carNum = carNum + member.getCarNumber();
        }

        newLoginInfo.setCarNumber(carNum);
        newLoginInfo.setMemberType(member.getMemberType());
        //
        //MemberInfo memberInfo=new MemberInfo();
        //memberInfo.setMemberId(member.getMemberId());
        //memberInfo.setLastLoginTime(new Date());
        memberInfoService.updateLogin(member.getMemberId());


        newLoginInfo.setLastPlatformMsgTime(member.getLastPlatformMsgTime());
        newLoginInfo.setLastCustomMsgTime(member.getLastCustomMsgTime());

        return newLoginInfo;
    }
}
